import java.util.ArrayList;
import java.util.HashMap;
import java.util.StringTokenizer;


public class MovieTheater extends Thread{
	Server server;
	private int numberOfSeatsInTheather = 20;
	private int numberOfSeatsReserved = 0;
	private HashMap<String, Integer> seats = new HashMap<String, Integer>();
	private String[] seatAssignment = new String[numberOfSeatsInTheather];	
	private boolean inCS = false;
	
	public MovieTheater(Server server) {
		this.server = server;
		for(int i = 0; i < seatAssignment.length; i++) {
			seatAssignment[i] = "";
		}
	}
	
		
	public void process(){ 
		System.out.println("printOutMsg");
		ArrayList<String> queue;
				
		while(true){
			String output = "";
			try {
				while(!okayCS()){
					System.out.println("waiting");
					synchronized(this){
						wait();
						System.out.println("awake");
					}
					
					// Check if need to synchronize
					if(server.needsSync()){
						// Sync
						String sync = server.getSync();
						
						// Process Command
						handleClient(sync);
						
						System.out.println(server.getIP() + " synced ");
						for(int i = 0; i < seatAssignment.length; i++) {
							System.out.print(seatAssignment[i] + " ");
						}
						System.out.println("");
						
						// Clear Sync
						server.clearSync();
					}
					
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String data = server.getCommand();
			if(data!= null && data.length() > 0) {
				System.out.println("Entering CS");
				inCS = true;
				try {
					Thread.sleep(8000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
					
				output = handleClient(data);
				
				server.output(output);
				System.out.println("Exiting CS");
				server.release();
			} else {
				System.out.println("Entering CS");
				System.out.println("// Request to sync from any server that is up");
				System.out.println("Exiting CS");
				server.release();
			}
		}
	}
	
	public void setCS(boolean value){
		inCS = value;
	}
	
	public boolean getCS() {
		return inCS;
	}
	
	private String handleClient(String data) {
		System.out.println("Movie Theater Command => " + data);
		String output = "";
		StringTokenizer st = new StringTokenizer(data);			
		String command = st.nextToken().trim();		
					
		// Process normal command
		if(command.equalsIgnoreCase("reserve")){
			String name = st.nextToken().trim();						
			Integer seats = Integer.parseInt(st.nextToken().trim());
			output = reserve(name, seats);				
		} else if(command.equalsIgnoreCase("search")){
			String searchTerm = st.nextToken().trim();
			output = search(searchTerm);
		} else if(command.equalsIgnoreCase("delete")){
			output = delete(st.nextToken().trim());
		} 
		return output;
	}
	
	private boolean okayCS() {
		int[] serverIPs = server.getIPs();
		int myIP = server.getIP();
		String data = server.getCommand();
		
		// Checking if requesting Critical Section, if not, return false;
		if(data != null && data.length() > 0) {
			
	        for (int j = 0; j < serverIPs.length; j++){
	        	System.out.println("Q " + myIP + " " + server.getQueue(myIP) + " " + serverIPs[j] + " " + server.getQueue(serverIPs[j]));
	        	System.out.println("C " + myIP + " " + server.getQueue(myIP) + " " + serverIPs[j] + " " + server.getClock(serverIPs[j]));
	        	
	        	// -2 means the server is not up
	        	if(server.getClock(serverIPs[j]) != -1 && serverIPs[j]!=myIP) {
		            if (isGreater(server.getQueue(myIP), myIP, server.getQueue(serverIPs[j]), serverIPs[j])) {
		            	System.out.println(myIP + " cannot enter CS 1");
		                return false;
		            }
		            if (isGreater(server.getQueue(myIP), myIP, server.getClock(serverIPs[j]), serverIPs[j])) {
		            	System.out.println(myIP + " cannot enter CS 2");
		                return false;
		            }	            
	        	}
	        }
		} else {
			/*
			System.out.println("data is null");
			if(server.getQueue(myIP) == -1) {
				return false;
			} else {
				System.out.println("queue is not -1");
			}*/			
			return false;
		}
        return true;
    }
	
	private boolean isGreater(int entry1, int pid1, int entry2, int pid2) {
        if (entry2 == -1) return false;
        return ((entry1 > entry2) || ((entry1 == entry2) && (pid1 > pid2)));
    }
	
	private String search(String name) {
		
		// Enter Critical Section		
		String output = "-1";
		if(seats.containsKey(name)){
			output = "";
			for(int i = 0; i < seatAssignment.length; i++){
				if(seatAssignment[i]!=null){
					if(seatAssignment[i].equalsIgnoreCase(name)){
						output += i + " "; 
					}
				}
			}
		}

		return output;
	}
	
	private String delete(String name){
		String output = "-1";
		if(seats.containsKey(name.toLowerCase())) {
			output = "";
			for(int i = 0; i < seatAssignment.length; i++) {
				if(seatAssignment[i]!=null){
					if(seatAssignment[i].equalsIgnoreCase(name)){
						output += i + " ";
						seatAssignment[i] = "";
						numberOfSeatsReserved--;
					}
				}
			}
			seats.remove(name.toLowerCase());
		}
		
		return output;
	}
	
	private synchronized String reserve(String name, int numberOfSeats){
				
		// Enter Critical Section
		//System.out.println("Entering CS");		
		String output = "";
		
		// if reserving the number of seats requested + the number of seats already reserved is more
		// than the number of seats available, then return -1
		if((numberOfSeatsReserved+numberOfSeats) > numberOfSeatsInTheather){
			output = "-1";
		} else if(seats.containsKey(name)){
			// if user is already in the map that means he has already reserved tickets
			output = "-2";
		} else {
			System.out.println("reserve 0");
			// put user into reserved list
			seats.put(name.toLowerCase(), numberOfSeats);
			System.out.println("reserve 1");
			// assign seats
			for(int i = 0; i < numberOfSeats ; i++) {
				System.out.println("reserve 2");
				for(int x = 0; x < seatAssignment.length; x++){
					System.out.println("reserve 3");
					if(seatAssignment[x] == null || seatAssignment[x].isEmpty()){		
						System.out.println("Reserving seat " + x);
						seatAssignment[x] = name.toLowerCase();
						output += x + " ";
						break;
					} else {						
						if(seatAssignment[x] == null) {
							System.out.println("reserve 4 is null " + seatAssignment[x]);
						} else {
							System.out.println("reserve 4 is not null " + seatAssignment[x]);
						}
					}
				}
			}
			
			// increase the number of seats reserved
			numberOfSeatsReserved+=numberOfSeats;
		}
		
		return output;
	}
	
	public void setSeatAssignments(String[] seatsIn) {
		seatAssignment = seatsIn;
		seats = new HashMap<String, Integer>();
		for(int i = 0; i < seatAssignment.length; i++) {
			if(seatAssignment!=null){
				if(seats.containsKey(seatAssignment[i])) {
					seats.put(seatAssignment[i], seats.get(seatAssignment[i])+1);
				} else {
					seats.put(seatAssignment[i], 1);
				}
			}
		}
	}
	
	public String[] getSeatAssignments() {
		return seatAssignment;
	}
	
	public int getNumberofSeats() {
		return numberOfSeatsInTheather;
	}
	
	public void run(){		
		process();
	}
}
